home *** CD-ROM | disk | FTP | other *** search
- /*
- * volops.c - routines for misc volume operations
- */
- #include "RevRdist.h"
- #include <HyperXCmd.h>
- #include <stdarg.h>
- #include <string.h>
- #include <Errors.h>
- #include "volops.h"
-
- /*
- * list of volumes we have unmounted and so might need to remount
- */
- struct mchain
- {
- Handle next;
- AFPVolMountInfo info;
- };
- typedef struct mchain mchain;
- static Handle Remount_list; /* first mchain entry */
- /*
- * Volume we mounted and so might need to unmount
- */
- static Integer Mounted_vref;
-
- pascal void callback(void);
- OSErr callxcmd (Integer, Handle *rh, ...);
- OSErr mountsvr (AFPVolMountInfo *, Boolean);
- Handle ptoch (Str31);
- void unmount_conflicts (Integer, AFPVolMountInfo *);
-
-
-
- /*
- *=========================================================================
- * accessMaster(fn, mi) - gain access to master folder
- * entry: fn = name of master folder
- * mi = ptr to AppleShare info to mount folder
- * exit: returns 0 on success, *rh possibly updated
- * else OSErr
- *=========================================================================
- */
- OSErr
- accessMaster (StringPtr fn, AFPVolMountInfo *mi)
- {
- OSErr error;
- CInfoPBPtr cp;
- int pass;
- char *s;
- StringPtr sn; /* server name */
- HParamBlockRec pb;
- Str31 volName;
-
- cp = (CInfoPBPtr) &pb;
- for (pass = 0; pass < 3; pass++)
- {
- /*
- * See if we have see files, see folders access to master folder
- */
- ZEROAT(cp);
- cp->dirInfo.ioNamePtr = fn;
- error = PBGetCatInfo (cp, false);
- if (error == 0)
- if ((cp->dirInfo.ioFlAttrib & ioDirMask) == 0)
- error = dupFNErr;
- if (error == 0)
- if ((pb.accessParam.ioACUser & 0x03) != 0)
- error = afpAccessDenied;
- if (error == 0)
- return 0; /* got it */
-
- /*
- * Try various things to get master folder mounted
- */
- switch (pass)
- {
- case 0:
- /*
- * First, simply try mounting the volume containing it
- */
- sn = (StringPtr)mi + mi->serverNameOffset;
- if (sn[0] == 0)
- return error; /* if no server, can do nothing */
- error = mountsvr (mi, true);
- break;
- case 1:
- /*
- * If that didn't do it, we may need to unmount conflicting
- * volumes and then try mounting again.
- */
- ZERO(pb);
- s = (char *)mi + mi->volNameOffset;
- COPYPS (s, volName);
- if (volName[volName[0]] != ':')
- volName[++volName[0]] = ':';
- pb.volumeParam.ioNamePtr = volName;
- pb.volumeParam.ioVolIndex = -1;
- error = PBGetVInfo ((ParmBlkPtr)&pb, false);
- unmount_conflicts (error ? 0 : pb.volumeParam.ioVRefNum, mi);
- error = mountsvr (mi, true);
- if (error == 0)
- break;
- }
- }
- return error ? error : dirNFErr;
- }
-
-
-
- /*
- *=========================================================================
- * callback () - dummy XCMD callback routine
- * should never be called
- *=========================================================================
- */
- pascal
- void
- callback ()
- {
- }
-
-
-
- /*
- *=========================================================================
- * callxcmd (xh, rh [,args]) - call XCMD with args
- * entry: resid = resource id of XCMD resource
- * rh = ptr to handle to contain XCMD result
- * args = Str255's to pass to XCMD
- * returns: 0 if no errors, else OSErr
- *=========================================================================
- */
- OSErr
- callxcmd (Integer resid, Handle *rh, ...)
- {
- va_list ap;
- OSErr error;
- int i;
- StringPtr sp;
- Handle h;
- struct XCmdBlock cb; /* XCMD parameter block */
- typedef pascal void (*xcmd)(struct XCmdBlock *);
-
- /*
- * Convert args from Strings to handles to C strings and stash in parameter
- * block.
- */
- va_start (ap, rh);
- error = memFullErr;
- ZERO (cb);
- for (i = 0; i < (sizeof(cb.params)/sizeof(cb.params[0]));)
- {
- sp = va_arg (ap, StringPtr);
- if (sp == 0)
- break;
- cb.params[i++] = h = ptoch (sp);
- if (h == 0)
- goto cleanup;
- }
- /*
- * Fill in the rest of the parameter block and call the XCMD
- */
- error = 0;
- cb.paramCount = i;
- cb.entryPoint = (ProcPtr) callback;
- h = GetResource ('XCMD', resid);
- if (!h)
- {
- error = ResError();
- if (error == 0)
- error = resNotFound;
- goto cleanup;
- }
- HLock (h);
- (*(xcmd)(*h)) (&cb); /* call the XCMD */
- HUnlock (h);
- ReleaseResource(h);
- /*
- * dispose of our strings, etc.
- */
- cleanup:
- va_end (ap);
- for (--i; i >= 0; --i)
- {
- if (h = cb.params[i])
- DisposHandle (h);
- }
- *rh = cb.returnValue; /* check the result */
- return error;
- }
-
-
-
- /*
- *=========================================================================
- * findWvol (vn, flags, volp) - find first volume matching criteria
- * entry: vn = str255 to hold vol name
- * flags = bits selecting criteria FF_xxx
- * volp = pointer to Integer to hold volume refnum
- * returns: 0 if found, else OSErr
- *=========================================================================
- */
- OSErr
- findWvol (StringPtr vn, int flags, Integer *volp)
- {
- OSErr error;
- int i;
- HParamBlockRec hpb; /* HFS parameter block */
- GetVolParmsInfoBuffer vib; /* for GetVolParms */
-
- ZERO (hpb);
- hpb.volumeParam.ioNamePtr = vn;
- for (i = 1; ; i++)
- {
- vn[0] = 0;
- hpb.volumeParam.ioVRefNum = 0;
- hpb.volumeParam.ioVolIndex = i;
- error = PBHGetVInfo (&hpb, false);
- if (error)
- break;
- if (flags & FF_WRITE && hpb.volumeParam.ioVAtrb & 0x8080)
- continue; /* skip if S/W or H/W locked */
- if (flags & FF_NOSONY && hpb.volumeParam.ioVDRefNum == -5)
- continue; /* skip if Sony driver */
- if (flags & FF_NOXFS && hpb.volumeParam.ioVFSID)
- continue; /* skip if foreign file system */
- if (flags & ~(FF_WRITE|FF_NOSONY))
- {
- ZERO(vib);
- hpb.ioParam.ioBuffer = (Ptr) &vib;
- hpb.ioParam.ioReqCount = sizeof (vib);
- error = PBHGetVolParms (&hpb, false);
- if (error && error != paramErr)
- continue;
- if (error == 0)
- {
- if (flags & FF_NOXFS && vib.vMAttrib & (1<<bHasExtFSVol))
- continue; /* another check for foreign fs */
- if (flags & FF_NOASHARE && vib.vMServerAdr)
- continue;
- }
- error = 0;
- }
- *volp = hpb.volumeParam.ioVRefNum;
- break;
- }
- return error;
- }
-
-
- /*
- *=========================================================================
- * mountsvr (mi, flag) - try to mount volume from server
- * entry: mi = pointer to mounting information
- * flag = true if should record mounted volume
- * returns: 0 if volume mounted
- * <> 0 on error
- *=========================================================================
- */
- static
- OSErr
- mountsvr (AFPVolMountInfo *mi, Boolean flag)
- {
- OSErr error;
- int i; /* temp index */
- Handle rh; /* XCMD response handle */
- StringPtr sv; /* server volume name */
- StringPtr zn; /* zone name */
- StringPtr sn; /* server name */
- StringPtr un; /* user name */
- StringPtr pw; /* user password */
- ParamBlockRec pb; /* simple parameter block */
- HParamBlockRec hpb; /* HFS parameter block */
- Str255 volName; /* returned volume name */
- AFPVolMountInfo micopy; /* copy of mi parameter */
-
- rh = 0;
- sv = (StringPtr)mi + mi->volNameOffset;
- /*
- * PBVolumeMount does not reliably return afpAlreadyMounted,
- * so check ourselves if already mounted.
- */
- ZERO (hpb);
- hpb.volumeParam.ioNamePtr = volName;
- for (i = 1, error = 0; ! error; i++)
- {
- volName[0] = 0;
- hpb.volumeParam.ioVRefNum = 0;
- hpb.volumeParam.ioVolIndex = i;
- error = PBHGetVInfo (&hpb, false);
- if (error == 0 && EqualString (sv, volName, false, true))
- {
- return 0;
- }
- }
- /*
- * PBVolumeMount alters the mounting information record, so we
- * make a copy and let it alter the copy.
- */
- ZERO(pb);
- micopy = *mi;
- pb.ioParam.ioBuffer = (Ptr)&micopy;
- error = PBVolumeMount (&pb);
- if (error && error != paramErr && error != afpAlreadyMounted)
- return error;
- if (error == afpAlreadyMounted)
- flag = false; /* don't record mount by us */
- sv = (StringPtr)mi + mi->volNameOffset;
- if (error == paramErr)
- {
- /*
- * An error of paramErr really means that the PBVolumeMount HFSDispatch
- * subfunction is not supported.
- * Use the Apple Mount XCMD to try to mount the volume from
- * an AppleShare server.
- */
- zn = (StringPtr)mi + mi->zoneNameOffset;
- sn = (StringPtr)mi + mi->serverNameOffset;
- un = (StringPtr)mi + mi->userNameOffset;
- pw = (StringPtr)mi + mi->userPasswordOffset;
- error = callxcmd (RSRC_MOUNT, &rh, zn, sn, sv,
- un[0] ? un : NULL, pw[0] ? pw : NULL, NULL);
- if (rh && *rh && **rh)
- error = fnfErr;
- if (error)
- goto cleanup;
- }
- /*
- * Now, scan to make sure the volume was really mounted
- */
- ZERO (hpb);
- hpb.volumeParam.ioNamePtr = volName;
- for (i = 1, error = 0; ! error; i++)
- {
- volName[0] = 0;
- hpb.volumeParam.ioVRefNum = 0;
- hpb.volumeParam.ioVolIndex = i;
- error = PBHGetVInfo (&hpb, false);
- if (EqualString (sv, volName, false, true))
- {
- /*
- * Found it, everything is cool.
- */
- if (flag)
- Mounted_vref = hpb.volumeParam.ioVRefNum;
- break;
- }
- }
- cleanup:
- if (rh)
- DisposHandle (rh);
- return error;
- }
-
-
-
- /*
- *=========================================================================
- * ptoch (ps) - copy pascal string to c string in new handle
- * entry: ps = ptr to pascal string
- * returns: handle to null-terminated copy of string
- * 0 if cannot allocate handle
- *=========================================================================
- */
- static
- Handle
- ptoch (ps)
- register unsigned char *ps;
- {
- register Handle h;
- register int i;
- register unsigned char *s;
-
- i = ps[0];
- h = NewHandle ((Size) (i + 1));
- if (h)
- {
- for (s = (unsigned char *)(*h); i; i--)
- *s++ = *++ps;
- *s = 0;
- }
- return h;
- }
-
-
-
-
- /*
- *=========================================================================
- * remount_vols () - remount volumes unmounted by unmount_conflicts
- * entry: Remount_list points to chain of mount information
- * returns: OSErr
- *=========================================================================
- */
- OSErr
- remount_vols (void)
- {
- OSErr error;
- Handle h, next, prev; /* links */
- mchain *mp; /* current mount chain entry */
- OSErr result;
-
- /*
- * The remount chain is current in backward order, reverse it
- */
- result = 0;
- for (prev = 0, h = Remount_list; h ; h = next)
- {
- mp = (mchain *)(*h);
- next = mp->next;
- mp->next = prev;
- prev = h;
- }
- Remount_list = prev;
- /*
- * Now mount the volumes
- */
- for (h = Remount_list; h ; h = next)
- {
- HLock (h);
- mp = (mchain *)(*h);
- next = mp->next;
- error = mountsvr (&mp->info, false);
- HUnlock (h);
- if (error)
- result = error;
- DisposHandle (h);
- }
- Remount_list = 0;
- return result;
- }
-
-
- /*
- *=========================================================================
- * unmount (vol) - unmount a volume
- * entry: vol = vRefNum to of volume to unmount
- * returns: OSErr
- *=========================================================================
- */
- OSErr
- unmount (vol)
- Integer vol;
- {
- OSErr error;
- ParamBlockRec pb;
-
- Clue0 = "\punmount";
- if (vol == 0)
- return 0;
- if (vol == BootVol)
- return 0;
- ZERO(pb);
- pb.volumeParam.ioVRefNum = vol;
- error = PBUnmountVol (&pb);
- if (error)
- {
- ClueID = error;
- panic (true, E_SYS, Clue0, "\pPBUnmountVol", nil);
- }
- return error;
- }
-
-
- /*
- *=========================================================================
- * unmount_conflicts (volref, mi) - unmount volumes from given server
- * entry: volref = refnum of a mounted volume from server
- * = 0 if none known
- * mi = ptr to mount info
- * Mounted_vref = vref of volume we have mounted
- * exit: volumes which might conflict with remounting of specified
- * volume have been unmounted
- * Information needed to remount them added to Remount_list.
- *=========================================================================
- */
- static
- void
- unmount_conflicts (Integer volref, AFPVolMountInfo *mi)
- {
- AFPVolMountInfo *ami; /* info about mounted vol */
- Integer cinfosize; /* current size of ami */
- mchain *cp; /* chain pointer */
- OSErr error;
- Handle h; /* temp handle */
- int i; /* vol index */
- Integer infosize; /* size needed to hold vol info */
- char *s; /* temp ptr into ami */
- Longint serverAdr; /* network address of server */
- Integer t; /* temp */
- Integer vref; /* vRefNum of current volume */
- HParamBlockRec pb;
- GetVolParmsInfoBuffer vib;
- Str31 volName; /* name of mounted vol */
-
- serverAdr = 0;
- if (volref)
- {
- ZERO (pb);
- ZERO (vib);
- pb.ioParam.ioVRefNum = volref;
- pb.ioParam.ioBuffer = (Ptr)&vib;
- pb.ioParam.ioReqCount = sizeof(vib);
- error = PBHGetVolParms(&pb, false);
- if (error == paramErr)
- return; /* system does not support needed calls */
- if (error == 0)
- {
- serverAdr = vib.vMServerAdr;
- if (serverAdr == 0)
- return; /* if not network volume, no conflicts */
- }
- }
- /*
- * Scan the mounted volumes looking for conflicting volumes
- */
- rescan:
- cinfosize = 0;
- h = 0;
- ZERO (pb);
- ZERO (vib);
- pb.volumeParam.ioNamePtr = volName;
- error = 0;
- for (i = 1; ; i++)
- {
- volName[0] = 0;
- pb.volumeParam.ioVRefNum = 0;
- pb.volumeParam.ioVolIndex = i;
- error = PBHGetVInfo (&pb, false);
- if (error)
- break; /* error should mean end of vol list */
- pb.ioParam.ioBuffer = (Ptr) &vib;
- pb.ioParam.ioReqCount = sizeof(vib);
- error = PBHGetVolParms(&pb, false);
- if (error && error != paramErr)
- break; /* give up on error */
- /*
- * If this volume is not networked, cannot conflict
- */
- if (error == paramErr || vib.vMServerAdr == 0)
- continue;
- /*
- * If we know the server address and this vol is at a different address,
- * it cannot conflict
- */
- if (serverAdr && serverAdr != vib.vMServerAdr)
- continue;
- /*
- * We will probably unmount this volume, so get the remounting info
- * for it
- */
- vref = pb.ioParam.ioVRefNum;
- if (vref != Mounted_vref)
- {
- ZERO(pb);
- infosize = 0;
- pb.ioParam.ioVRefNum = vref;
- pb.ioParam.ioBuffer = (Ptr)&infosize;
- pb.ioParam.ioReqCount = sizeof(infosize);
- error = PBGetVolMountInfoSize((ParmBlkPtr)&pb);
- /*
- * There are three possible outcomes from this call:
- * It succeeds, which means we should be able to get
- * the mounting info.
- * It fails with error paramErr, which means we are
- * running on an early system. In this case,
- * we unmount all network volumes because we cannot
- * tell which are safe to leave mounted.
- * It fails some other way, so we skip this volume.
- */
- if (error == paramErr || infosize < sizeof(*ami))
- infosize = sizeof (*ami);
- if (infosize > cinfosize) /* get a handle big enough for info */
- {
- if (h)
- DisposHandle (h);
- h = NewHandle(infosize + sizeof(Handle));
- if (h == 0)
- {
- cinfosize = 0;
- continue;
- }
- cinfosize = infosize;
- }
- HLock(h);
- cp = (mchain *)(*h);
- ami = &cp->info;
- if (error == 0)
- {
- pb.ioParam.ioBuffer = (Ptr)ami;
- pb.ioParam.ioReqCount = cinfosize;
- error = PBGetVolMountInfo((ParmBlkPtr)&pb);
- }
- if (error && error != paramErr) {
- HUnlock(h);
- continue;
- }
- /*
- * If GetVolMountInfo not supported, fake answer by
- * assuming all network volumes are from same server
- * and under guest account
- */
- if (error == paramErr)
- {
- s = ami->AFPData;
- ZEROAT(ami);
- ami->length = infosize;
- ami->media = mi->media;
- ami->uamType = kNoUserAuthentication;
- if (t = mi->zoneNameOffset)
- COPYPS((char *)mi + t, s);
- ami->zoneNameOffset = s - (char *)ami; s += 32;
- if (t = mi->serverNameOffset)
- COPYPS((char *)mi + t, s);
- ami->serverNameOffset = s - (char *)ami; s += 32;
- COPYPS(volName, s);
- ami->volNameOffset = s - (char *)ami; s += 32;
- ami->userNameOffset = s - (char *)ami; s += 32;
- ami->userPasswordOffset = s - (char *)ami; s += 32;
- ami->volPasswordOffset = s - (char *)ami;
- } else {
- /*
- * If different servers, skip volume
- */
- if (!EqualString ((unsigned char *)mi + mi->serverNameOffset,
- (unsigned char *)ami + ami->serverNameOffset,
- false, true))
- {
- HUnlock(h);
- continue;
- }
- }
- HUnlock(h);
- }
- /*
- * Need to unmount this volume
- */
- error = unmount (vref);
- if (error)
- {
- if (Quit)
- return;
- continue;
- }
- /*
- * If not vol mounted by selves, add to list of unmounted vols
- */
- if (vref == Mounted_vref)
- {
- Mounted_vref = 0;
- }
- else
- {
- cp = (mchain *)(*h);
- cp->next = Remount_list;
- Remount_list = h;
- }
- /*
- * Now, have to rescan from top, since vols get renumbered when
- * one is unmounted.
- */
- goto rescan;
- }
- if (h)
- DisposHandle(h);
- }
-
-
-
-
- /*
- *=========================================================================
- * unmount_mounted (vol) - unmount volumes we mounted
- * entry: vol = vRefNum to unmount in addition to Mounted_vref
- * returns: OSErr
- *=========================================================================
- */
- OSErr
- unmount_mounted (Integer vol)
- {
- OSErr error;
-
- error = 0;
- if (vol && vol != Mounted_vref)
- error = unmount (vol);
- if (Mounted_vref)
- error = unmount (Mounted_vref);
- Mounted_vref = 0;
- return error;
- }